/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#ifndef __ENVELOPETEMPLATES_H__
#define __ENVELOPETEMPLATES_H__

#include <math.h>
#include "Keys.h"

namespace liba
{
namespace animate
{

/*====================================================================
range()

Given the value v of a periodic function, returns the equivalent value
v2 in the principal interval [lo, hi].  If i isn't NULL, it receives
the number of wavelengths between v and v2.

   v2 = v - i * (hi - lo)

For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
======================================================================*/

template< typename T >
T range( T v, T lo, T hi, int * count )
{
	T len( hi - lo );
	
	if( len == T(0) )
	{
		*count = 0;
		return lo;
	}

	*count = int(floor( (v - lo)/len ));
	return v - len * (*count);
}

/*====================================================================
outgoing()

Return the outgoing tangent to the curve at key0.  The value returned
for the BEZ2 case is used when extrapolating a linear pre behavior and
when interpolating a non-BEZ2 span.
====================================================================== */

template< typename T >
T outgoing( typename KeysTCB< T >::iterator key0, typename KeysTCB< T >::iterator key1, typename KeysTCB< T >::iterator key_prev, typename KeysTCB< T >::iterator end )
{
	float a, b, t;
	T d, out;
	
	a = ( 1.0f - (float)key0->tension )
		* ( 1.0f + (float)key0->continuity )
		* ( 1.0f + (float)key0->bias );
	b = ( 1.0f - (float)key0->tension )
		* ( 1.0f - (float)key0->continuity )
		* ( 1.0f - (float)key0->bias );
	d = key1->value - key0->value;
		
	if ( key_prev != end )
	{
        t = 0.5;//float(( key1->time - key0->time ) / ( key1->time - key_prev->time ));
        out = t * ( a * ( key0->value - key_prev->value ) + b * d );
	}
	else
        out = b * d;

	return out;
}

/*====================================================================
incoming()

Return the incoming tangent to the curve at key1.  The value returned
for the BEZ2 case is used when extrapolating a linear post behavior.
====================================================================== */

template< typename T >
T incoming( typename KeysTCB< T>::iterator key0, typename KeysTCB< T >::iterator key1, typename KeysTCB< T >::iterator key_next, typename KeysTCB< T >::iterator end )
{
	float a, b, t;
	T d, in;
	
	a = ( 1.0f - (float)key1->tension )
		* ( 1.0f - (float)key1->continuity )
		* ( 1.0f + (float)key1->bias );
	b = ( 1.0f - (float)key1->tension )
		* ( 1.0f + (float)key1->continuity )
		* ( 1.0f - (float)key1->bias );
	d = key1->value - key0->value;
	
	if ( key_next != end )
	{
        t = 0.5;//float(( key1->time - key0->time ) / ( key_next->time - key0->time ));
        in = t * ( b * ( key_next->value - key1->value ) + a * d );
	}
	else
        in = a * d;

	return in;
}

} // namespace animate
} // namespace liba
using namespace liba;


#endif //__ENVELOPETEMPLATES_H__
